import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;


public class Server implements Runnable{

	public static final int port = 4444;
	
	private Socket socket;
	private Race race;
	
	public Server (Socket socket, Race race){
		this.socket = socket;
		this.race = race;
	}
	
	public void run(){
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			PrintWriter pr = new PrintWriter (socket.getOutputStream());
			String text = br.readLine();
			
			if (text.equals("CHECKPOINT")){
				
				int checkPoint = Integer.parseInt(br.readLine());
				int dorsal = Integer.parseInt(br.readLine());

				System.out.println("Dorsal: "+dorsal+"\nCheckpoint: "+checkPoint+"\nTime: "+(new Date()).toString());
				long retValue = race.checkPoint(dorsal, checkPoint, new Date());
				
				switch((int)retValue){
					case Race.ERROR_INVALID_CHECKPOINT: pr.write("Checkpoint invalid!\n"); break;
					case Race.ERROR_PREVIOUS_CHECKPOINT: pr.write("Racer has already passed a checkpoint ahead of this one\n"); break;
					case Race.ERROR_SAME_CHECKPOINT: pr.write("Racer has already been checked\n"); break;
					case Race.ERROR_SKIPPED_CHECKPOINT: pr.write("Racer has skipped a checkpoint\n"); break;
					case Race.ERROR_INVALID_DORSAL: pr.write("Racer with that dorsal is not registered in the server\n"); break;
					default: pr.write("OK\n");
				}
				
				pr.flush();
			}
			
			else if (text.equals("REFRESH")){
				for (Athlete ath : race.getClassification()){
					pr.write("RACER\n");
					pr.write(ath.getRace_number()+"\n");
					pr.write(ath.getName()+"\n");
					if (ath.getLastPassage()==Race.NOT_STARTED)
						pr.write("NO\n");
					else
						pr.write("YES\n");
					pr.write(ath.getStringTime(1)+"\n");
					pr.write(ath.getStringTime(2)+"\n");
					pr.write(ath.getStringTime(3)+"\n");
				}
				pr.write("END\n");
				pr.flush();
			}
			
			else {
				System.out.println("Invalid message received");
				pr.write("ERROR\n");
				pr.flush();
			}
			
			br.close();
			pr.close();
			
			socket.close();	
		}
		catch (IOException ioEx){
			System.out.println("IOException: " + ioEx.getMessage());
		}
	}
	
	public static void main(String args[]){
		ServerSocket serverSocket;
		Race race = new Race();
		
		try {
			race.loadAthletes("bttrace.xlsx");
			serverSocket = new ServerSocket(port);
			System.out.println("Server started\nIP: "+InetAddress.getLocalHost().getHostAddress()+"\nPort: "+serverSocket.getLocalPort());

			do {
				Socket socket = serverSocket.accept();
				(new Thread (new Server(socket,race))).start();
			} 
			while(!race.isOver());
			
			serverSocket.close();
		}
		catch (InvalidFormatException invEx){
			System.out.println("InvalidFormatException: " + invEx.getMessage());
			return;
		}
		catch (IOException ioEx){
			System.out.println("IOException: " + ioEx.getMessage());
			return;
		}
		
	}

}
